package com.abcdefg.lotterysystem.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.abcdefg.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.abcdefg.lotterysystem.common.exception.ServiceException;
import com.abcdefg.lotterysystem.common.utils.JWTUtils;
import com.abcdefg.lotterysystem.common.utils.RegexUtils;
import com.abcdefg.lotterysystem.controller.param.ShortMessageLoginParam;
import com.abcdefg.lotterysystem.controller.param.UserLoginParam;
import com.abcdefg.lotterysystem.controller.param.UserPasswordLoginParam;
import com.abcdefg.lotterysystem.controller.param.UserRegisterParam;
import com.abcdefg.lotterysystem.dao.dataobject.Encrypt;
import com.abcdefg.lotterysystem.dao.dataobject.UserDO;
import com.abcdefg.lotterysystem.dao.mapper.UserMapper;
import com.abcdefg.lotterysystem.service.UserService;
import com.abcdefg.lotterysystem.service.VerificationCodeService;
import com.abcdefg.lotterysystem.service.dto.UserDTO;
import com.abcdefg.lotterysystem.service.dto.UserLoginDTO;
import com.abcdefg.lotterysystem.service.dto.UserRegisterDTO;
import com.abcdefg.lotterysystem.service.enums.UserIdentityEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private VerificationCodeService verificationCodeService;
    @Override
    public UserRegisterDTO register(UserRegisterParam param) {
        //验证注册信息
        checkRegisterInfo(param);

        //加密数据（构造dao请求）
        UserDO userDO = new UserDO();
        userDO.setUserName(param.getName());
        userDO.setEmail(param.getMail());
        userDO.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        userDO.setIdentity(param.getIdentity());
        if (StringUtils.hasText(param.getPassword())) {
            userDO.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        }
        //保存数据
        userMapper.insert(userDO);
        //构造返回
        UserRegisterDTO userRegisterDTO=new UserRegisterDTO();
        userRegisterDTO.setUserId(userDO.getId());
        return userRegisterDTO;
    }

    @Override
    public UserLoginDTO login(UserLoginParam param) {
        UserLoginDTO userLoginDTO;
        //类型的检查与转换
        if(param instanceof UserPasswordLoginParam loginParam){
            userLoginDTO=loginByUserPassword(loginParam);
        }else if(param instanceof ShortMessageLoginParam loginParam){
            userLoginDTO=loginByShortMessage(loginParam);
        }else{
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIST);
        }

        return userLoginDTO;
    }


    @Override
    public List<UserDTO> findUserInfo(UserIdentityEnum identity) {
        String identityString=null==identity?null:identity.name();
        //查表
        List<UserDO> userDOList = userMapper.selectUserListByIdentity(identityString);
        List<UserDTO> userDTOList=userDOList.stream().map(
                userDO -> {
                    UserDTO userDTO = new UserDTO();
                    userDTO.setUserId(userDO.getId());
                    userDTO.setUserName(userDO.getUserName());
                    userDTO.setEmail(userDO.getEmail());
                    userDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    userDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
                    return userDTO;
                }
        ).collect(Collectors.toList());
        return userDTOList;
    }

    /**
     * 密码登录
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByUserPassword(UserPasswordLoginParam loginParam) {
        UserDO userDO=null;
        //进行身份的验证
        //先进行手机号或邮箱验证
        if(RegexUtils.checkMail(loginParam.getLoginName())){
            userDO=userMapper.selectByMail(loginParam.getLoginName());
        } else if (RegexUtils.checkMobile(loginParam.getLoginName())) {
            // 手机号登录
            // 根据手机号查询用户表
            userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginName()));

        }else{
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);
        }

        if(userDO==null){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        }else if(userDO.getPassword()==null){
            //判断是否进行强制身份登录
            if(StringUtils.hasText(loginParam.getMandatoryIdentity())
                    && !loginParam.getMandatoryIdentity()
                    .equalsIgnoreCase(userDO.getIdentity())){
                //登录身份不通过
                throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
            }
        }else if(!DigestUtil.sha256Hex(loginParam.getPassword()).equals(userDO.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //填入返回值

        Map<String,Object> claims=new HashMap<>();
        claims.put("id",userDO.getId());
        claims.put("identity",userDO.getIdentity());
        String token = JWTUtils.genJwt(claims);

        UserLoginDTO userLoginDTO=new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }

    /**
     * 短信验证码登录
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByShortMessage(ShortMessageLoginParam loginParam) {
        UserDO userDO=null;

        if(!RegexUtils.checkMail(loginParam.getEmail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        System.out.println("获取邮箱地址:"+loginParam.getEmail());
        System.out.println("通过邮箱获取用户信息:"+userMapper.selectByMail(loginParam.getEmail()));
        // 获取用户数据
         userDO = userMapper.selectByMail(loginParam.getEmail());
        if (null == userDO) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(loginParam.getMandatoryIdentity())
                && !loginParam.getMandatoryIdentity()
                .equalsIgnoreCase(userDO.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //获取验证码
        String code=verificationCodeService.getVerificationCode(loginParam.getEmail());
        if (!loginParam.getVerificationCode().equals(code)) {
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }
        //填入返回值

        Map<String,Object> claims=new HashMap<>();
        claims.put("id",userDO.getId());
        claims.put("identity",userDO.getIdentity());
        String token = JWTUtils.genJwt(claims);

        UserLoginDTO userLoginDTO=new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;
    }


    private void checkRegisterInfo(UserRegisterParam param) {
        if (null == param) {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }
        // 校验邮箱格式 xxx@xxx.xxx
        if (!RegexUtils.checkMail(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        // 校验手机号格式
        if (!RegexUtils.checkMobile(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }

        // 校验身份信息
        if (null == UserIdentityEnum.forName(param.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

        // 校验管理员密码必填
        if (param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())
                && !StringUtils.hasText(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }

        // 密码校验，至少6位
        if (StringUtils.hasText(param.getPassword())
                && !RegexUtils.checkPassword(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        // 检验邮箱是否被使用
        if(checkMailUsed(param.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);
        }
        //检验手机号是否被使用
        if(checkPhoneNumberUsed(param.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);
        }

    }

    private boolean checkPhoneNumberUsed(String phoneNumber) {
        if(userMapper.countByPhone(new Encrypt(phoneNumber))>0){
            return true;
        }
        return false;
    }

    private boolean checkMailUsed(String mail) {
        if(userMapper.countByMail(mail)>0){
            return true;
        }
        return false;
    }
}
